package com.vilen.learn.java7.V4.V4_3;

import com.vilen.learn.java7.V4.Author;
import com.vilen.learn.java7.V4.SimpleMicroBlogNode;
import com.vilen.learn.java7.V4.Update;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 有缺陷的解决死锁问题的尝试
 * Created by vilen on 2017/10/2.
 */
public class FlawedFixDeadlockWithLockMicroBlogNode implements SimpleMicroBlogNode{

    private static Update getUpdate(String s) {
        Update.Builder b = new Update.Builder();
        b.updateText(s).author(new Author("Ben"));
        return b.build();
    }

    private final String ident;
    private final Lock lock = new ReentrantLock();

    public FlawedFixDeadlockWithLockMicroBlogNode(String ident_) {
        ident = ident_;
    }

    @Override
    public String getIdent() {
        return ident;
    }

    @Override
    public void propagateUpdate(Update upd_, SimpleMicroBlogNode backup_) {
        boolean acquired = false;
        while (!acquired) {
            try {
                //尝试与锁定，超时时长随机
                int wait = (int) (Math.random() * 10);
                acquired = lock.tryLock(wait, TimeUnit.MILLISECONDS);
                if (acquired) {
                    System.out.println(ident + ": recvd: " + upd_.getUpdateText()
                            + " ; backup: " + backup_.getIdent());
                    //在其他线程上确认
                    backup_.confirmUpdate(this, upd_);
                } else {
                    Thread.sleep(wait);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //仅在锁定时解锁
                if (acquired) {
                    lock.unlock();
                }
            }
        }
    }

    @Override
    public void confirmUpdate(SimpleMicroBlogNode other_, Update upd_) {
        boolean acquired = false;
        while (!acquired) {
            try {
                int wait = (int) (Math.random() * 10);
                acquired = lock.tryLock(wait, TimeUnit.MILLISECONDS);
                if (acquired) {
                    System.out.println(ident + ": recvd confirm: " + upd_.getUpdateText()
                            + " from " + other_.getIdent());
                } else {
                    Thread.sleep(wait);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (acquired) {
                    lock.unlock();
                }
            }
        }
    }

    public static void main(String[] a) {
        final FlawedFixDeadlockWithLockMicroBlogNode local = new FlawedFixDeadlockWithLockMicroBlogNode(
                "localhost:8888");
        final FlawedFixDeadlockWithLockMicroBlogNode other = new FlawedFixDeadlockWithLockMicroBlogNode(
                "localhost:8988");
        final Update first = getUpdate("1");
        final Update second = getUpdate("2");

        new Thread(new Runnable() {
            public void run() {
                local.propagateUpdate(first, other);
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                other.propagateUpdate(second, local);
            }
        }).start();
    }

}
